# 模块使用
import threading, websocket, websocket_server
import time, json, re, os
from urllib.parse import quote, unquote

# 外部引用
from werkzeug._reloader import run_with_reloader

# 自身调用
from .config import config
from .notice_request import *
from .parse_handler import parse, parse_invoke
from .plugin import load_plugins
from .app import bot
from .util import jsonify

# 公共调用
bot.jsonify = jsonify


class SingletonType(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

class InvokeServer(threading.Thread):
    def run(self):
        print('开始创建ws服务器, port:', config.self_server_port)
        bot.server = websocket_server.WebsocketServer(config.self_server_port, "0.0.0.0")
        bot.server.set_fn_new_client(self.client_enter)
        bot.server.set_fn_client_left(self.client_left)
        bot.server.set_fn_message_received(self.msg_received)
        bot.server.run_forever()

    def client_enter(self, client, server):
        print('客户', client['id'], '进入了')

    def client_left(self, client, server):
        print('客户', client['id'], '退出了')

    def msg_received(self, client, server, raw_info):
        try:
            info = json.loads(raw_info)
            if info.get('event') == 'invoke':
                print(info)
                threading.Thread(target=parse_invoke, args=(client, server, info)).start()
        except:
            msg = 'invoke 的内容格式不正确哦'
            print(msg)
            bot.server.send_message(client, msg)


class CreateWsBot(threading.Thread, metaclass=SingletonType):
    def __init__(self, plugin_dirs=['bot/plugins'], enable_invoke=False):
        threading.Thread.__init__(self)
        bot.config = config
        self.bot_server_port = config.bot_server_port
        self.reconnect_interval = config.get('reconnect_interval', 10)

        self.connect_server()
        if enable_invoke: 
            bot.server = InvokeServer()
            bot.server.start()
        self.init_notice_request()
        self.regist_plugin(plugin_dirs)

    def connect_server(self):
        print('开始连接ws服务器, port:', self.bot_server_port)
        while True:
            try:
                bot.client = websocket.create_connection(f'ws://localhost:{self.bot_server_port}/websocket')
                print('连接成功')
                break
            except ConnectionRefusedError:
                print(f'无法连接到ws服务器, {self.reconnect_interval} 秒后重新尝试连接')
                time.sleep(self.reconnect_interval)

    def init_notice_request(self):
        arg_type = bot.config.get('arg_type', 'list')
        bot.on_command = on_command(arg_type)
        bot.on_notice = on_notice(arg_type)
        bot.on_request = on_request(arg_type)
        bot.on_invoke = on_invoke(arg_type)
        bot.on_env = on_env(arg_type)

    def regist_plugin(self, plugin_dirs):
        for plugin_dir in plugin_dirs:
            plugin_dir = os.path.normpath(plugin_dir)
            module_prefix = plugin_dir.replace(os.sep, '.')
            load_plugins(plugin_dir, module_prefix)

    def run(self):
        print('等待命令解析')
        error_msg = None
        while True:
            try:
                raw_info = bot.client.recv()
                print(raw_info)
                threading.Thread(target=parse, args=(raw_info,)).start()
            except ConnectionRefusedError:
                error_msg = '无法连接到ws服务器'
            except ConnectionResetError:
                error_msg = '连接断开'

            if error_msg:
                print(f'{error_msg}, {self.reconnect_interval} 秒后重新尝试连接')
                time.sleep(self.reconnect_interval)
                try: 
                    bot.client = websocket.create_connection(f'ws://localhost:{self.bot_server_port}/websocket')
                    print('连接成功')
                except: pass
